package com.hospital.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hospital.dto.DeptBedQueryDTO;
import com.hospital.entity.Bed;
import com.hospital.entity.Department;
import com.hospital.entity.Ward;
import com.hospital.enumeration.BedStatus;
import com.hospital.enumeration.BusinessExceptionEnum;
import com.hospital.exception.BusinessException;
import com.hospital.mapper.BedMapper;
import com.hospital.mapper.DepartmentMapper;
import com.hospital.mapper.WardMapper;
import com.hospital.result.PageResult;
import com.hospital.service.BedService;
import com.hospital.service.util.DepartmentCheckUtil;
import com.hospital.vo.BedUsageVO;
import com.hospital.vo.DepartmentBedVO;
import com.hospital.vo.SpeDeptBedVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class BedServiceImpl extends ServiceImpl<BedMapper, Bed> implements BedService {
    @Autowired
    private BedMapper bedMapper;
    @Autowired
    private WardMapper wardMapper;
    @Autowired
    private DepartmentMapper departmentMapper;

    @Autowired
    private DepartmentCheckUtil departmentCheckUtil;

    /**
     * 给病人分配一个该科室的空床位
     * @param deptId
     * @return
     */
    @Override
    public Long assignBed(Long deptId) {
        // 1. 查询该科室的所有病房
        List<Long> wardIds = wardMapper.selectList(
                new LambdaQueryWrapper<Ward>()
                        .eq(Ward::getDeptId, deptId)
        ).stream().map(Ward::getWardId).collect(Collectors.toList());

        // 2. 查询该科室有无空床位
        Bed emptyBed = bedMapper.selectOne(
                new LambdaQueryWrapper<Bed>()
                        .in(Bed::getWardId, wardIds)
                        .eq(Bed::getStatus, BedStatus.AVAILABLE)
                        .last("LIMIT 1")
        );

        // 3. 如果没有空床位，则抛出异常
        if(emptyBed == null){
            throw new BusinessException(BusinessExceptionEnum.NO_AVAILABLE_BEDS);
        }

        // 4. 更新床位状态为占用
        emptyBed.setStatus(BedStatus.OCCUPIED);
        bedMapper.updateById(emptyBed);

        // 5. 返回床位id
        return emptyBed.getBedId();
    }

    /**
     * 获取所有科室的病床信息
     * @return
     */
    @Override
    public List<DepartmentBedVO> getDepartmentBedList() {
        List<Department> departments = departmentMapper.selectList(null);
        return departments.stream().map(department -> {
            DepartmentBedVO departmentBedVO = DepartmentBedVO.builder()
                    .deptId(department.getDeptId())
                    .deptName(department.getDeptName())
                    .build();

            // 查询该科室的所有病房
            List<Long> wardIds = wardMapper.selectList(
                    new LambdaQueryWrapper<Ward>()
                           .eq(Ward::getDeptId, department.getDeptId())
            ).stream().map(Ward::getWardId).collect(Collectors.toList());

            // 查询该科室的所有病床
            List<Bed> beds = bedMapper.selectList(
                    new LambdaQueryWrapper<Bed>()
                            .in(Bed::getWardId, wardIds)
            );

            departmentBedVO.setBedCount(beds.size());
            departmentBedVO.setAvailableBedCount((int) beds.stream().filter(bed -> bed.getStatus() == BedStatus.AVAILABLE).count());
            departmentBedVO.setOccupiedBedCount((int) beds.stream().filter(bed -> bed.getStatus() == BedStatus.OCCUPIED).count());

            return departmentBedVO;
        }).sorted(Comparator.comparing(DepartmentBedVO::getDeptId)).collect(Collectors.toList());
    }

    @Override
    public PageResult getDepartmentBedByDeptId(DeptBedQueryDTO deptBedQueryDTO) {
        Long deptId = deptBedQueryDTO.getDeptId();
        // 科室是否存在
        departmentCheckUtil.checkDepartment(deptId);

        IPage<SpeDeptBedVO> page = new Page<>(deptBedQueryDTO.getPageNumber(), deptBedQueryDTO.getPageSize());

        bedMapper.pageDeptBed(page, deptId);

        return PageResult.builder()
                .total(page.getTotal())
                .records(page.getRecords())
                .build();
    }

    @Override
    public List<BedUsageVO> getBedUsage() {
        Integer countOccupiedBed = bedMapper.selectList(
                new LambdaQueryWrapper<Bed>()
                        .eq(Bed::getStatus, BedStatus.OCCUPIED)
        ).size();

        Integer countAvailableBed = bedMapper.selectList(
                new LambdaQueryWrapper<Bed>()
                        .eq(Bed::getStatus, BedStatus.AVAILABLE)
        ).size();

        // 创建床位使用情况VO列表并填充数据
        return Arrays.asList(
                new BedUsageVO(BedStatus.OCCUPIED, countOccupiedBed),
                new BedUsageVO(BedStatus.AVAILABLE, countAvailableBed)
        );
    }
}
